package com.java.string.StringBuilder.source_analyze.source_code;

import java.util.Arrays;

public abstract class AbstractStringBuilder {
    // 存字符串的字符数组
    char[] value;
    // 字符实际数量
    int count;
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    AbstractStringBuilder() {}
    
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
    
    // 重载的append方法很多，此处以String类型为例
    public AbstractStringBuilder append(String str) {
        // 字符串为空，则新增字符串"null"
        if (str == null)
            return appendNull();
        
        int len = str.length();
        
        // 与真正扩容步骤②③④相关的入口在此⭐⭐⭐
        ensureCapacityInternal(count + len);
        
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    
    private AbstractStringBuilder appendNull() {
        int c = count;
        
        // 与真正扩容步骤②③④相关的入口在此⭐⭐⭐
        ensureCapacityInternal(c + 4);
        
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }
    
    private void ensureCapacityInternal(int minimumCapacity) { // 参数为加上新增加元素后的扩容最小容量
        // ②原容量能存下新添加的元素，则无需扩容直接存
        if (minimumCapacity - value.length > 0) {
            // 扩容。newCapacity求扩容后的容量
            value = Arrays.copyOf(value, newCapacity(minimumCapacity));
        }
    }
    
    private int newCapacity(int minCapacity) {
        // ③原容量无法存下新添加的元素但根据(原容量*2+2)求得的扩容容量能存下新添加的元素，则扩容为(原容量*2+2)后存
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            // ④原容量无法存下新添加的元素且根据(原容量*2+2)求得的扩容容量也无法存下新添加的元素，则扩容为加上新增加元素后的实际容量存
            newCapacity = minCapacity;
        }
        
        // 扩容后容量非法时进入hugeCapacity方法进行大容量扩容
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity;
    }
    
    private int hugeCapacity(int minCapacity) {
        // 加上新增加元素后的扩容最小容量超出Integer最大值则抛出异常
        if (Integer.MAX_VALUE - minCapacity < 0) {
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE) ? minCapacity : MAX_ARRAY_SIZE;
    }
    
    public int capacity() {
        return value.length;
    }
    
    @Override
    public abstract String toString();
}
